#include <cassert>
#include <iostream>
#include "Epoller.hpp"
#include <sys/epoll.h>
#include <string>
#include "err.hpp"
#include "log.hpp"
#include "Sock.hpp"
#include <unordered_map>
#include <functional>
#include "Util.hpp"
#include "Protocol.hpp"
using namespace std;
static const int N = 128;
struct Connection;
class EpollServer;
using call_back_t = function<void(Connection *)>;
using func_t = function<Response(const Request &)>;
struct Connection
{
public:
    Connection(const int fd, const string &clientip, const uint16_t clientport)
        : _fd(fd), _clientip(clientip), _clientport(clientport)
    {
    }

    void Register(call_back_t reader, call_back_t writer, call_back_t excepter)
    {
        _reader = reader;
        _writer = writer;
        _excepter = excepter;
    }

    // IO信息
    int _fd;
    string _inbuffer;
    string _outbuffer;

    // 用户信息，debug
    string _clientip;
    uint16_t _clientport;

    // IO处理函数
    call_back_t _reader;
    call_back_t _writer;
    call_back_t _excepter;

    // 需要关心的事件
    int _events;

    // 回指指针
    EpollServer *_ptr;
};
class EpollServer
{
public:
    EpollServer(func_t func, uint16_t port = 8888)
        : _func(func), _port(port)
    {
    }

    void Init()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        _epoller.Create();
        AddConnection(_listensock.GetSock(), EPOLLIN | EPOLLET);
        LogMessage(Debug, "listensock adds successful");
    }

    // 事件派发器
    void Dispatcher()
    {
        int timeout = -1; // 阻塞
        while (true)
        {
            LoopOnce(timeout);
        }
    }

    void LoopOnce(int timeout)
    {
        LogMessage(Debug, "Loop is starting");
        int n = _epoller.Wait(eparray, N, timeout);
        for (int i = 0; i < n; i++)
        {
            int events = eparray[i].events;
            int fd = eparray[i].data.fd;
            // 我们将所有的异常情况，最后全部转化成为recv，send的异常
            if ((eparray[i].events & EPOLLERR) || (eparray[i].events & EPOLLHUP))
            {
                events |= (EPOLLIN | EPOLLOUT);
            }
            if ((events & EPOLLIN) && ConExist(fd))
            {
                _connections[fd]->_reader(_connections[fd]);
            }
            else if ((events & EPOLLOUT) && ConExist(fd))
            {
                _connections[fd]->_writer(_connections[fd]);
            }
        }
    }

    bool ConExist(int fd)
    {
        return _connections.find(fd) != _connections.end();
    }

    void AddConnection(const int fd, int events, const uint16_t clientport = 8888, const string &clientip = "127.0.0.1")
    {
        // 1. 设置fd是非阻塞
        if (events & EPOLLET)
            Util::NonBlock(fd);
        // 2. 构建connection对象，交给connections_来进行管理
        Connection *con = new Connection(fd, clientip, clientport);
        if (fd == _listensock.GetSock())
        {
            con->_reader = bind(&EpollServer::Accepter, this, placeholders::_1);
        }
        else
        {
            con->_reader = bind(&EpollServer::Reader, this, placeholders::_1);
            con->_writer = bind(&EpollServer::Writer, this, placeholders::_1);
            con->_excepter = bind(&EpollServer::Excepter, this, placeholders::_1);
        }
        con->_events = events;
        con->_ptr = this;
        _connections.insert(make_pair(fd, con));
        // 3.fd && events 写透到内核中
        _epoller.AddModEvent(fd, events, EPOLL_CTL_ADD);
        LogMessage(Debug, "AddConnection is done....");
    }

    void EnableWriterReader(int fd, bool reader, bool writer)
    {
        int events = 0;
        events |= ((reader ? EPOLLIN : 0) | (writer ? EPOLLOUT : 0) | EPOLLET);
        _epoller.AddModEvent(fd, events, EPOLL_CTL_MOD);
    }
    // 连接管理器
    void Accepter(Connection *con)
    {

        do
        {
            string clientip;
            uint16_t clientport;
            int err;
            // 1. 新连接到来
            int sock = _listensock.Accept(clientip, clientport, err);
            if (sock > 0)
            {
                LogMessage(Debug, "%s:%d已经连上服务器了", clientip.c_str(), clientport);
                // 1.1 此时在这里，我们能不能进行recv/read ? 不能，只有epoll知道sock上面的事件情况，将sock添加到epoll中
                AddConnection(sock, EPOLLIN | EPOLLET, clientport, clientip);
            }
            else
            {
                if ((err == EWOULDBLOCK) || (err == EAGAIN))
                {
                    break;
                }
                else if (err == EINTR)
                {
                    continue;
                }
                else
                {
                    LogMessage(Warning, "Listensock error,errno:%d,errorstring:%s", errno, strerror(errno));
                    continue;
                }
            }

        } while (con->_events & EPOLLET);
        LogMessage(Debug, "Accepter is done...");
    }

    void HandleRequest(Connection *con)
    {
        bool flag = true;
        while (flag)
        {
            string requeststr;
            int n = ReadPackage(con->_inbuffer, requeststr);
            if (n > 0)
            {
                // 1.去报头
                requeststr = DelHeader(requeststr, n);
                Request req;
                // 2.反序列化
                req.Deserialization(requeststr);
                // 3.交付上层处理
                Response resp = _func(req); // request 保证是一个完整的请求报文！
                // 4.序列化
                string respstr;
                resp.Serialize(respstr);
                // 5.添加报头
                respstr = AddHeader(respstr);
                // 6.返回
                con->_outbuffer += respstr;
            }
            else
            {
                flag = false;
            }
        }
    }

    bool HandleReader(Connection *con)
    {
        bool flag = true;
        // 读取完毕本轮数据！
        int fd = con->_fd;
        do
        {
            char buff[1024];
            ssize_t n = read(fd, buff, sizeof(buff) - 1);
            if (n > 0)
            {
                buff[n] = 0;
                con->_inbuffer += buff;
            }
            else if (n == 0)
            {
                con->_excepter(con);
                break;
            }
            else
            {
                if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    con->_excepter(con);
                    flag = false;
                    break;
                }
            }

        } while (con->_events & EPOLLET);

        return flag;
    }

    void Reader(Connection *con)
    {
        if (!HandleReader(con))
        {
            return;
        }
        HandleRequest(con);
        if (!con->_outbuffer.empty())
        {
             // 一般我们在面对写入的时候，直接写入，没写完，才交给epoll！
            con->_writer(con);// 只是第一次触发发送
        }
        //LogMessage(Debug, "Reader is done...");
    }


    void Writer(Connection *con)
    {
        bool flag=true;
        do
        {
            int fd = con->_fd;
            ssize_t n = write(fd, (con->_outbuffer).c_str(), (con->_outbuffer).size());
            if (n > 0)
            {
                con->_outbuffer.erase(0, n);
                if ((con->_outbuffer).empty())
                {
                    break;
                }
            
            }
            else
            {
                if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
                {

                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    con->_excepter(con);
                    flag=false;
                    break;
                }
            }
        } while (con->_events & EPOLLET);
        if(!flag)
        {
            return;
        }
        if(!con->_outbuffer.empty())
        {
            EnableWriterReader(con->_fd,true,true);
        }
        else
        {
            EnableWriterReader(con->_fd,true,false);
        }
        //LogMessage(Debug, "Writer is done...");
    }

    void Excepter(Connection *con)
    {
        //1.从epoll中移除
        _epoller.DelEvent(con->_fd);
        //2.关闭文件描述符
        close(con->_fd);
        //3.把con从_connections中移除
        _connections.erase(con->_fd);
        //4.释放con指针
        delete con;
    }

private:
    uint16_t _port;
    Sock _listensock;
    Epoller _epoller;
    struct epoll_event eparray[N];
    unordered_map<int, Connection *> _connections;
    func_t _func;
};